package com.ican.nc;


import java.io.File;
import java.util.ArrayList;
import java.util.List;

import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.util.PropertyFilter;

import org.htmlcleaner.CommentNode;
import org.htmlcleaner.ContentNode;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ican.common.SystemConstants;
import com.ican.domain.product.ProductAttribute;
import com.ican.domain.product.ProductImage;
import com.ican.domain.rule.ParseRule;
import com.ican.service.product.ProductService;
import com.ican.util.DateUtils;
import com.ican.util.ImageFetchUtil;
import com.ican.util.MD5Util;
import com.ican.util.NcSysConfigUtil;
import com.ican.util.ValidateUtil;

public class ParseUtil {
    private final static Logger logger = LoggerFactory.getLogger(ParseUtil.class); 
    private static String imgCenterRootPath;
    private static String imgCenterHttp;
    private static String ocImgRootPath;
    private static String ocServerHttp;
    
    /**  /home/linlinapp/imgcenter/  */
    public static String getImgCenterRootPath() {
        if(imgCenterRootPath == null){
            imgCenterRootPath = NcSysConfigUtil.getValue("image.center.root.path");
        }
        return imgCenterRootPath;
    }
    /**  http://img.linlinapp.com:9931/   */
    public static String getImgCenterHttp() {
        if(imgCenterHttp == null){
            imgCenterHttp = NcSysConfigUtil.getValue("image.center.http");
        }
        return imgCenterHttp;
    }
    /** /home/linlinapp/oc/image/data/   */
    public static String getOcImgRootPath() {
        if(ocImgRootPath == null){
            ocImgRootPath = NcSysConfigUtil.getValue("oc.image.root.path");
        }
        return ocImgRootPath;
    }
    /** http://www.linlinapp.com:9931/ */
    public static String getOcServerHttp() {
        if(ocServerHttp == null){
            ocServerHttp = NcSysConfigUtil.getValue("oc.server.http");
        }
        return ocServerHttp;
    }
    /** 2012/01/01/   */
    public static String getDatePath() {
        String date = DateUtils.DatetoString(null, DateUtils.DATE_PATTERN_2);
        return date.substring(0,4) + File.separator + date.substring(4, 6) + File.separator + date.substring(6) + File.separator;
    }
    
    public static Object[] evaluateXPath(TagNode tn, String xpath){
        if(xpath == null || xpath.length() < 1){
            return null;
        }
        try {
            String[] xpaths = xpath.split("\\|");//可以解析多个结果
            if(xpaths.length == 1){
                return tn.evaluateXPath(xpath.trim());
            }
            
            List<Object[]> listTemp = new ArrayList<Object[]>();
            Object[] result = null;
            for(String xt : xpaths){
                result = tn.evaluateXPath(xt.trim());
                if(result != null && result.length > 0){
                    listTemp.add(result);
                }
            }

            result = null;
            if(listTemp.size() > 0){
                int size = 0;
                for(Object[] o : listTemp){
                    size = size + o.length;
                }
                result = new Object[size];
                size = 0;
                for(Object[] os : listTemp){
                    for(Object o : os){
                        result[size] = o;
                        size = size + 1;
                    }
                }
            }
            return result;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }
    
    public static Object getTagNode(Object[] os, RuleItem item){
        if(os == null || os.length == 0){
            return null;
        }
        if(item == null){
            return os[0];
        }
        int i = 0;
        if(ValidateUtil.stringIsInt(item.getObjIndex())){
            i = Integer.parseInt(item.getObjIndex());
        }
        if(i < 1 || i >= os.length){
            return os[0];
        }
        return os[i];
    }
    
    public static String parseResult(String result, RuleItem item){
        if(result == null || result.length() < 1 || item == null || item.getPaseOrder() == null){
            return result;
        }
        String[] orders = item.getPaseOrder().split("-");
        for(String s : orders){
            if(SystemConstants.PARSE_ORDER_HTTP.equals(s)){
                if(item.getHttp() != null){
                    result = item.getHttp() + result;
                }
            }else if(SystemConstants.PARSE_ORDER_REPLACE.equals(s)){
                if(item.getReplaceFrom() != null){
                    String[] fs = item.getReplaceFrom().split("\\|");//可以多次替换，以|分隔
                    String[] ts = null;
                    if(item.getReplaceTo() != null){
                        ts = item.getReplaceTo().split("\\|");
                    }
                    for(int i = 0; i < fs.length; i++){
                        if(ts == null || ts.length < fs.length){
                            result = result.replaceAll(fs[i], "");
                        }else{
                            result = result.replaceAll(fs[i], ts[i]);
                        }
                    }
                }
            }else if(SystemConstants.PARSE_ORDER_SPLIT.equals(s)){
                if(item.getSplitStr() != null){
                    String[] split = result.split(item.getSplitStr());
                    if(ValidateUtil.stringIsInt(item.getSplitIndex())){
                        int pi = Integer.parseInt(item.getSplitIndex());
                        if(pi > 0){
                            if(pi < split.length){
                                result = split[pi];
                            }else{
                                result = split[0];
                            }
                        }else if(pi < 0){
                            if(pi + split.length >= 0){
                                result = split[pi + split.length];
                            }else{
                                result = split[0];
                            }
                        }else{
                            result = split[0];
                        }
                    }else{
                        result = split[0];
                    }
                }
            }else if(SystemConstants.PARSE_ORDER_SUBSTR.equals(s)){
                int from = 0;
                if(item.getSubStrFrom() != null && item.getSubStrFrom().length() > 0){
                    from = result.indexOf(item.getSubStrFrom());
                }else if(ValidateUtil.stringIsInt(item.getSubIndexFrom())){
                    from = Integer.parseInt(item.getSubIndexFrom());
                    if(from < 0){
                        from = result.length() + from;
                    }
                }
                if(from < 0 || from >= result.length()){
                    from = 0;
                }
                int to = 0;
                if(item.getSubStrTo() != null && item.getSubStrTo().length() > 0){
                    to = result.lastIndexOf(item.getSubStrTo());
                }else if(ValidateUtil.stringIsInt(item.getSubIndexTo())){
                    to = Integer.parseInt(item.getSubIndexTo());
                    if(to < 0){
                        to = result.length() + to;
                    }
                }
                if(to <= from || to >= result.length()){
                    to = result.length();
                }
                result = result.substring(from, to);
            }
        }
        return result;
    }
    
    public static String tagNodeText(Object obj){
        if(obj == null){
            return null;
        }
        if(obj instanceof TagNode){
            TagNode t = (TagNode)obj;
            if(t.getChildren() != null && t.getChildren().size() > 0){
                Object o = t.getChildren().get(0);
                if(o instanceof ContentNode){
                    return ((ContentNode)o).getContent().toString().trim().replaceAll("\\?&amp;", "?").replaceAll("\r", "").replaceAll("\n", "");
                }else if(o instanceof CommentNode){
                    return ((CommentNode)o).getContent().toString().trim().replaceAll("\\?&amp;", "?").replaceAll("\r", "").replaceAll("\n", "");
                }else{
                    return t.getText().toString().trim().replaceAll("\\?&amp;", "?").replaceAll("\r", "").replaceAll("\n", "");
                }
            }else{
                return t.getText().toString().trim().replaceAll("\\?&amp;", "?").replaceAll("\r", "").replaceAll("\n", "");
            }
        }
        return obj.toString().trim().replaceAll("\\?&amp;", "?").replaceAll("\r", "").replaceAll("\n", "");
    }
    
    public static String tagNodeHtml(HtmlCleaner html, TagNode tagNode, RuleItem item){
        if(html == null || tagNode == null || item == null){
            return null;
        }
        try{
            //取出所有的A标签
            Object[] as = tagNode.evaluateXPath(item.getXpath() + "//a");
            if(as != null && as.length > 0){
                for(Object o : as){
                    if(o instanceof TagNode){
                        TagNode n = (TagNode)o;
                        n.setAttribute("href", "#");
                    }
                }
            }
            //取出所有图片
            Object[] imgs = tagNode.evaluateXPath(item.getXpath() + "//img");
            String http = item.getHttp() == null ? "" : item.getHttp();
            if(imgs != null && imgs.length > 0){
                String localPath = getDatePath() + "imgdesc" + File.separator;
                String imgRootPath = getImgCenterRootPath() + localPath;
                String imgRootHttp = getImgCenterHttp() + localPath;
                for(int i = 0; i < imgs.length; i++){
                    Object o = imgs[i];
                    if(o instanceof TagNode){
                        TagNode n = (TagNode)o;
                        String fileName = ImageFetchUtil.loadAndWriteImageNoException(http + n.getAttributeByName("src"), imgRootPath, null, i);
                        n.setAttribute("src", imgRootHttp + fileName);
                        n.setAttribute("localPath", localPath + fileName);
                    }
                }
            }
            Object[] desc = tagNode.evaluateXPath(item.getXpath());
            if(desc != null && desc.length > 0){
                if(desc[0] instanceof TagNode){
                    return html.getInnerHtml((TagNode)desc[0]);
                }else{
                    return desc[0].toString().trim().replaceAll("\r", "").replaceAll("\n", "");
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }
    
    public static String loadCommon(TagNode tagNode, RuleItem item) {
        if(tagNode == null || item == null){
            return null;
        }
        try {
            Object[] objs = evaluateXPath(tagNode, item.getXpath());
            if(objs == null || objs.length <1){
                return null;
            }
            int i = 0;
            if(item != null && ValidateUtil.stringIsInt(item.getObjIndex())){
                i = Integer.parseInt(item.getObjIndex());
            }
            Object obj = null;
            if(i < 1 || i >= objs.length){
                obj = objs[0];
            }else{
                obj = objs[i];
            }
            if(obj instanceof TagNode && item.getChildNodes() != null && item.getChildNodes().length() > 0){
                objs = evaluateXPath((TagNode)obj, item.getChildNodes());
                if(objs != null && objs.length > 0){
                    obj = objs[0];
                }
            }
            return parseResult(tagNodeText(obj), item);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    public static boolean loadImage(TagNode tagNode, RuleItem item, Integer productId, ProductService productService) {
        if(tagNode == null || item == null || productId == null || productService == null){
            return false;
        }
        boolean bo = true;
        try {
            Object[] images = evaluateXPath(tagNode, item.getXpath());
            if(images != null && images.length > 0){
                String localPath = getDatePath();
                String imgRootPath = getImgCenterRootPath() + localPath;
                String imgRootHttp = getImgCenterHttp() + localPath;
                for(int i = 0; i < images.length; i++){
                    String imgUrl =  parseResult(tagNodeText(images[i]), item);
                    String fileName = ImageFetchUtil.loadAndWriteImageNoException(imgUrl, imgRootPath, null, i);
                    if(fileName != null){
                        String code = MD5Util.Md5(imgUrl);
                        List<ProductImage> pis = productService.findProductImageByProductIdAndCode(productId, code);
                        if(pis == null || pis.size() < 1){
                            ProductImage pi = new ProductImage();
                            pi.setProductId(productId);
                            pi.setCode(code);
                            pi.setLocalPath(localPath + fileName);
                            pi.setPictureUrl(imgRootHttp + fileName);
                            productService.addProductImage(pi);
                        }
                    }
                }
            }
        } catch (Exception e) {
            bo = false;
            logger.error(e.getMessage(), e);
        }
        return bo;
    }
    
    public static boolean loadAttr(TagNode tagNode, RuleItem attrItem, RuleItem valueItem, 
                                Integer productId, Integer langId, ProductService productService) {
        if(tagNode == null || attrItem == null || valueItem == null || 
                productId == null || langId == null || productService == null){
            return false;
        }
        boolean bo = true;
        try {
            //解析属性、属性编码、属性值、属性值编码
            Object[] attrTns = evaluateXPath(tagNode, attrItem.getXpath());
            Object[] valueTns = evaluateXPath(tagNode, valueItem.getXpath());
            if(attrTns == null || valueTns == null || attrTns.length != valueTns.length){
                return false;
            }
            //判断是否有二级解析
            String[] valChildXpath = null;
            if(valueItem.getChildNodes() != null && valueItem.getChildNodes().length() > 0){
                valChildXpath = valueItem.getChildNodes().split(",");
            }
            for(int i = 0; i < attrTns.length; i++){
                //属性
                String attr = parseResult(tagNodeText(attrTns[i]), attrItem);
                //属性值
                if(valueTns[i] instanceof TagNode){
                    //需要扫描二级节点
                    if(valChildXpath != null){
                        TagNode valueTn = (TagNode)valueTns[i];
                        for(String vc : valChildXpath){
                            //属性选项
                            Object[] valChildTns = evaluateXPath(valueTn, vc);
                            if(valChildTns != null && valChildTns.length > 0){
                                for(Object vcTn : valChildTns){
                                    loadAttr2(attr, parseResult(tagNodeText(vcTn), valueItem), productId, langId, productService);
                                }
                            }
                        }
                    }else{
                        loadAttr2(attr, parseResult(tagNodeText(valueTns[i]), valueItem), productId, langId, productService);
                    }
                }else{
                    loadAttr2(attr, parseResult(tagNodeText(valueTns[i]), valueItem), productId, langId, productService);
                }
            }
        } catch (Exception e) {
            bo = false;
            logger.error(e.getMessage(), e);
        }
        return bo;
    }
    
    public static void loadAttr2(String attr, String value, Integer productId, Integer langId, ProductService productService){
        if(attr == null || attr.length() < 1){
            return;
        }
        ProductAttribute pa = new ProductAttribute();
        pa.setOptionName(attr);
        pa.setOptionValue(value);
        pa.setProductId(productId);
        pa.setLangId(langId);
        try{
            List<ProductAttribute> pas = productService.findProductAttr(productId, attr, value, langId);
            if(pas == null || pas.size() < 1){
                productService.addProductAttr(pa);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
    
    private static JsonConfig jsonConfig = new JsonConfig(); 
    static{
        jsonConfig.setRootClass(RuleItem.class);
        jsonConfig.setJavaPropertyFilter(new PropertyFilter() {
            @Override
            public boolean apply(Object source, String name, Object value) {
                if(value == null || value.toString().length() < 1){
                    return true;
                }
                return false;
            }
        });
        jsonConfig.setJsonPropertyFilter(new PropertyFilter() {
            @Override
            public boolean apply(Object source, String name, Object value) {
                if(value == null || value.toString().length() < 1){
                    return true;
                }
                return false;
            }
        });
    }
    
    public static String ruleItem2Json(RuleItem item){
        try {
            return JSONObject.fromObject(item, jsonConfig).toString();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }
    
    public static RuleItem json2RruleItem(String json){
        try {
            return (RuleItem)JSONObject.toBean(JSONObject.fromObject(json), jsonConfig);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }
    
    public static void rule2RuleVo(ParseRule rule, ParseRuleVo ruleVo) {
        ruleVo.setId(rule.getId());
        ruleVo.setWebsiteId(rule.getWebsiteId());
        ruleVo.setRuleDesc(rule.getRuleDesc());
        
        ruleVo.setDpUrl(json2RruleItem(rule.getDpUrl()));
        ruleVo.setNextPage(json2RruleItem(rule.getNextPage()));
        
        ruleVo.setProductName(json2RruleItem(rule.getProductName()));
        ruleVo.setProductCode(json2RruleItem(rule.getProductCode()));
        ruleVo.setProductPrice(json2RruleItem(rule.getProductPrice()));
        ruleVo.setProductPriceUnit(json2RruleItem(rule.getProductPriceUnit()));
        ruleVo.setProductWeight(json2RruleItem(rule.getProductWeight()));
        ruleVo.setProductWeightUnit(json2RruleItem(rule.getProductWeightUnit()));
        ruleVo.setProductDescription(json2RruleItem(rule.getProductDescription()));
        
        ruleVo.setProductImage(json2RruleItem(rule.getProductImage()));
        
        ruleVo.setProductAttribute(json2RruleItem(rule.getProductAttribute()));
        ruleVo.setProductAttributeValue(json2RruleItem(rule.getProductAttributeValue()));
    }
    
    public static void ruleVo2Rule(ParseRuleVo ruleVo, ParseRule rule) {
        rule.setId(ruleVo.getId());
        rule.setWebsiteId(ruleVo.getWebsiteId());
        rule.setRuleDesc(ruleVo.getRuleDesc());
        
        rule.setDpUrl(ruleItem2Json(ruleVo.getDpUrl()));
        rule.setNextPage(ruleItem2Json(ruleVo.getNextPage()));
        
        rule.setProductName(ruleItem2Json(ruleVo.getProductName()));
        rule.setProductCode(ruleItem2Json(ruleVo.getProductCode()));
        rule.setProductPrice(ruleItem2Json(ruleVo.getProductPrice()));
        rule.setProductPriceUnit(ruleItem2Json(ruleVo.getProductPriceUnit()));
        rule.setProductWeight(ruleItem2Json(ruleVo.getProductWeight()));
        rule.setProductWeightUnit(ruleItem2Json(ruleVo.getProductWeightUnit()));
        rule.setProductDescription(ruleItem2Json(ruleVo.getProductDescription()));
        
        rule.setProductImage(ruleItem2Json(ruleVo.getProductImage()));
        
        rule.setProductAttribute(ruleItem2Json(ruleVo.getProductAttribute()));
        rule.setProductAttributeValue(ruleItem2Json(ruleVo.getProductAttributeValue()));
    }
    
    public static void main(String[] args){
//        RuleItem item = new RuleItem();
//        item.setHttp("http://www.baidu.com");
//        item.setSubStrFrom("/asdf/[class='sdfas']/@src");
//        String json = ruleItem2Json(item);
//        System.out.println(json);
//        RuleItem temp = json2RruleItem(json);
//        System.out.println(temp.getHttp());
//        System.out.println(temp.getSubStrFrom());
//        System.out.println(temp.getReplaceTo());
//        String t = "http://dfawe?&amp;p=3";
//        System.out.print(t.replaceAll("\\?&amp;", "?"));
    }
}
